home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- *
- * MODULE NAME : APING.C
- *
- * COPYRIGHTS:
- * This module contains code made available by IBM
- * Corporation on an AS IS basis. Any one receiving the
- * module is considered to be licensed under IBM copyrights
- * to use the IBM-provided source code in any way he or she
- * deems fit, including copying it, compiling it, modifying
- * it, and redistributing it, with or without
- * modifications. No license under any IBM patents or
- * patent applications is to be implied from this copyright
- * license.
- *
- * A user of the module should understand that IBM cannot
- * provide technical support for the module and will not be
- * responsible for any consequences of use of the program.
- *
- * Any notices, including this one, are not to be removed
- * from the module without the prior written consent of
- * IBM.
- *
- * AUTHOR: Peter J. Schwaller
- * VNET: PJS at RALVM6 Tie Line: 444-4376
- * Internet: pjs@ralvm6.vnet.ibm.com (919) 254-4376
- *
- * FUNCTION: Perform an echo test to a specified destination.
- * APING can be used when you are first installing APPC on
- * your computer to make sure you can connect to another
- * computer in the network. APING can also be used to
- * get an estimate of the delay time or throughput to another
- * computer in the network.
- *
- * AVAILABILITY:
- * These sample programs and source are also available on
- * CompuServe through the APPC Information Exchange. To get
- * to the APPC forum just type 'GO APPC' from any CompuServe
- * prompt. The samples are available in the Sample Programs
- * library section. Just search on the keyword CPICPGMS to
- * find all the samples in this series.
- *
- * Updates for the sample programs and support for many more
- * CPI-C platforms will also be made available on CompuServe.
- *
- * RELATED FILES:
- * See APING.DOC for detailed information.
- *
- *****************************************************************************/
-
- /*****************************************************************************
- * OVERVIEW of APING CPI-C Flows
- *
- * Client (APING) Server (APINGD)
- * -------------- ---------------
- * Set up conversation
- * Allocate -------------------> Accept Conversation
- * Exchange Version Numbers
- * Send Data -------------------> Receive
- * Receive <------------------- Send Data
- * For number of iterations (i)
- * For number of consecutive packets (c)
- * Send Data -------------------> Receive
- * For number of consecutive packets (c)
- * Receive <------------------- Send Data
- * Shut down the conversation
- * Deallocate (FLUSH)
- *****************************************************************************/
-
- /* The following definitions are needed for VM and MVS */
- #if defined(VM) || defined(MVS)
-
- /* All arguments on the command line should be passed to this program. */
- #pragma runopts(noexecops)
-
- /* The C/370 compiler requires that identifier be unique in the 1st 8 chars. */
- #define current_iteration curr_iteration
- #define current_concurrent curr_concurrent
-
- #endif
-
- /* My CPI-C include file */
- /* Hides CMC.H differences among platforms */
- #include "cpiccmc.h"
-
- /* Collection of routines with special ported version for each platform */
- #include "cpicport.h"
-
- /* standard C include files */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
-
- #ifndef TIME_NOT_SUPPORTED
- #ifndef AIX
- #include <time.h>
- #else
- #include <sys/time.h>
- #endif
- #endif
-
- /* CPI-C error handling routines */
- /* This file is supplied with APING */
- #include "cpicerr.h"
-
- /* CPI-C initialization routines */
- /* This file is supplied with APING */
- #include "cpicinit.h"
-
- /* Argument processing procedure */
- /* This file is supplied with APING */
- #include "getopt.h"
-
-
- /* CPI-C error handling info */
- CPICERR * cpicerr;
-
-
- /*
- * Max size of a data buffer. This is the largest size buffer that can
- * be specified on a call to CPI-C.
- */
- #define MAX_SIZE (0x7FFF)
-
- /* These are the defaults to be used if the user does not provide arguments */
- /* to override these values. */
- #define DEFAULT_TP_NAME "APINGD"
- #define DEFAULT_PARTNER "NETID.LUNAME"
- #define DEFAULT_MODE_NAME "#INTER"
- #define DEFAULT_SYM_DEST "APINGD"
-
- /* Define these here so we can make changes throughout the code. */
- #define PROGRAM_NAME "APING"
- #define PROGRAM_INFO "version 2.2"
- #define MAJOR_VERSION (2)
- #define MINOR_VERSION (2)
- #define LOG_FILE_NAME "aping.err"
- #define LOG_FILE_PATH "$LOGPATH"
-
- #define ONEWAY_MAJOR_VERSION (2)
- #define ONEWAY_MINOR_VERSION (2)
-
- /* function prototypes for procedures in this file */
- void exit_processing(void);
- void handler(int);
- void process_arguments(int argc,
- char *argv[],
- CPICINIT * cpicinit);
-
- #ifndef TIME_NOT_SUPPORTED
- ULONG get_time(void);
- #endif
-
-
- /*
- * The following variables are global to enable their use by the
- * exit_processing() subroutine.
- */
- ULONG number_iterations = 2; /* times through the loop */
- ULONG number_concurrent = 1; /* sends by each side per loop */
- ULONG current_iteration; /* which iteration is active */
- ULONG current_concurrent; /* which send/recv is active */
- #ifndef TIME_NOT_SUPPORTED
- ULONG total_time = 0; /* used to calculate averages */
- ULONG min_time = 0xFFFFFFFF; /* used for max elapsed time */
- ULONG max_time = 0; /* used for min elapsed time */
- double data_rate; /* Variable used to calculate */
- /* the data rate */
- #endif
- ULONG size = 100; /* size of data sends */
-
- int one_way_flag = 2; /* Was one way data requested */
- /* value of 2 means two way echo */
- /* value of 1 means one way */
-
- /*
- * Message displayed with show_info() when APING is started.
- */
- char * intro[] = {
- PROGRAM_NAME " " PROGRAM_INFO " APPC echo test with timings.",
- " by Peter J. Schwaller (pjs@ralvm6.vnet.ibm.com)",
- NULL
- };
-
- /*
- * Message displayed with show_info() when usage information is requested or
- * after an invalid flag was specified.
- */
- char * usage[] = {
- "",
- "APING [flags] destination",
- " destination",
- "\tmay be either a symbolic destination name or a partner LU name",
- " -m mode_name",
- "\tmode name (default: #BATCH)",
- " -t tp_name",
- "\tthe TP to start on the server (default: APINGD)",
- " -s N",
- "\tN is the size of the packet transmitted (default: 100 bytes)",
- " -i N",
- "\tN is the number of iterations (default: 2)",
- " -c N",
- "\tN is the number of consecutive packets sent by each side (default: 1)",
- " -1",
- "\tOnly send data from client to server (No echo)",
- " -u userid",
- " -p password",
- "\tSecurity parameters. If a userid is specified without a password,",
- "\tyou will be prompted for the password.",
- " -n",
- "\tDo not use any security (SECURITY=NONE).",
- "",
- #ifndef TIME_NOT_SUPPORTED
- "The minimum time, maximum time, and average time will be shown.",
- #endif
- NULL
- };
-
-
- void cdecl
- main( int argc, char *argv[])
- {
- /* Variables used for CPI-C calls */
- unsigned char cm_conv_id[8]; /* CPI-C conversation ID */
- CM_INT32 cm_rc; /* CPI-C return code */
- CM_INT32 length; /* generic length variable */
- CM_INT32 rts_received; /* request to send received */
- CM_INT32 max_receive_len; /* Max receive length on CMRCV */
- CM_INT32 what_received; /* What received parm from CMRCV */
- CM_INT32 received_len; /* Amount of data rcvd on CMRCV */
- CM_INT32 status_received; /* Status from CMRCV */
-
- /* Data buffer for send and receive */
- unsigned char CM_PTR buffer; /* CPIC data buffer */
-
- /* Destination information */
- CPICINIT * cpicinit;
-
- #ifndef TIME_NOT_SUPPORTED
- ULONG start_time = 0; /* when a ping starts */
- ULONG end_time; /* when a ping ends */
- ULONG elapsed_time; /* used for time calculations */
- #endif
-
- char partner_major_version;
- char partner_minor_version;
-
-
- /*
- * Make sure all output is seen as soon as possible.
- */
- setbuf(stdout, NULL);
-
- show_info(intro); /* Show program information */
-
-
- /*
- * Create a new CPICINIT structure and initialize values.
- * The procedures are in CPICINIT.C
- */
-
- cpicinit = cpicinit_new();
- cpicinit_default_tp_name(cpicinit, DEFAULT_TP_NAME);
- cpicinit_default_destination(cpicinit, DEFAULT_PARTNER);
- cpicinit_default_mode_name(cpicinit, DEFAULT_MODE_NAME);
- cpicinit_default_sym_dest_name(cpicinit, DEFAULT_SYM_DEST);
-
- /*
- * Process all of the command line arguments. All of the conversation
- * setup arguments are stored in the cpicinit object. The block size
- * and other loop parameters are set in the global variables.
- */
- process_arguments(argc, argv, cpicinit);
-
-
- if (cpicinit->set_destination == NOT_SET) {
- fprintf(stderr, "\n\aYou must specify a destination.\n");
- show_info(usage);
- exit(EXIT_FAILURE);
- }
-
- if (cpicinit_query_passwd_required(cpicinit)) {
- /* get a password from the user */
- cpicinit_get_passwd(cpicinit);
- }
-
- #if 0
- /* set up a signal handler, to clean up and display total upon exit */
- if (signal(SIGINT, SIG_IGN) == SIG_DFL)
- signal(SIGINT, handler);
- #endif
-
- buffer = (unsigned char CM_PTR)alloc_cpic_buffer((USHORT)size);
- /* allocate an APPC buffer */
-
-
-
- /*
- * Initialize the CPICERR structure. This is done before the CMINIT
- * call so that we can use CPICERR for help with errors on CMINIT.
- * The procedure is in CPICERR.C
- */
- cpicerr = cpicerr_new();
- cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
- cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
- cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
- cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
- cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
- cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
-
- cpicinit_setup_conversation(cpicinit, cm_conv_id, cpicerr);
-
- /*
- * Fill in conversation information for CPI-C error reporting.
- */
- cpicerr_set_conv_id(cpicerr, cm_conv_id);
-
- {
- CM_SYNC_LEVEL sync_level = CM_CONFIRM;
- cmssl(cm_conv_id, /* Set sync level */
- &sync_level,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSSL, cm_rc);
- }
-
- {
- CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
- cmsptr(cm_conv_id, /* Set prepare to receive type */
- &prep_to_receive,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
- }
-
-
- /*
- * Fill in conversation information for CPI-C error reporting.
- */
- cpicerr_set_conv_id(cpicerr, cm_conv_id);
-
- #ifndef TIME_NOT_SUPPORTED
- start_time = get_time(); /* let's time the allocate */
- #endif
-
- cmallc(cm_conv_id,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMALLC, cm_rc);
-
- #ifndef TIME_NOT_SUPPORTED
- end_time = get_time(); /* stop the timer */
-
- /* show the allocate time */
- printf("\nAllocate duration: %8lu ms\n",
- end_time - start_time);
- #endif
-
- #ifndef TIME_NOT_SUPPORTED
- start_time = get_time();
- #endif
-
- cpicerr_exchange_version(cpicerr,
- cm_conv_id,
- CM_SEND_STATE,
- &partner_major_version,
- &partner_minor_version);
-
- /*
- * If the one_way_flag has been set, we have to make sure that our
- * partner is at the correct version to accept one way data. If
- * the partner is not at the right level, we'll turn off the one
- * way flag and the partner will echo data (normal operating mode).
- *
- * Trying to use one way data with a partner that can't handle the
- * CONFIRM status indicator would result in an error on the partner
- * side. On this side, we would see DEALLOCATE_ABEND.
- */
- if ((one_way_flag == 1) &&
- !(partner_major_version > ONEWAY_MAJOR_VERSION ||
- (partner_major_version == ONEWAY_MAJOR_VERSION &&
- partner_minor_version >= ONEWAY_MINOR_VERSION))) {
- printf("\nOne way data transfer is not supported by partner.\n");
- printf("Partner will echo data.\n");
- one_way_flag = 2;
- }
-
- #ifndef TIME_NOT_SUPPORTED
- end_time = get_time(); /* stop the timer */
-
- /* show the startup time */
- printf("\nProgram startup and Confirm duration: %8lu ms\n\n",
- end_time - start_time);
- #endif
-
-
- printf(
- " Duration Data Sent Data Rate Data Rate\n");
- printf(
- " (msec) (bytes) (KB/s) (Mb/s) \n");
- printf(
- " -------- --------- --------- ---------\n");
-
-
- /*
- * Start current at zero so if a BREAK occurs, it will contain the number
- * of iterations completed. We take a slight risk in assuming that
- * the current_iteration++ operation is atomic.
- *
- * This loop encompasses both a send loop and a receive loop. Both
- * the send a receive loop are executed the number of times specified
- * by the number_iterations variable (set by the -i argument).
- */
- for (current_iteration = 0;
- current_iteration<number_iterations;
- current_iteration++ ) {
- {
- CM_SEND_TYPE send_type = CM_BUFFER_DATA;
- cmsst(cm_conv_id,
- &send_type,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
- }
-
- #ifndef TIME_NOT_SUPPORTED
- start_time = get_time();
- #endif
-
- for (current_concurrent = 1; /* Start current at one so we */
- current_concurrent<number_concurrent ; /* do one LESS send in */
- current_concurrent++ ) { /* loop than the specifed number */
-
- length = size;
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
-
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
-
- }
-
- /*
- * Set the send type to do a send and a prepare to receive. This will
- * send both the data and the send permission indicator to our
- * partner all at once.
- *
- * If the one_way_flag has been set, we will issue a Confirm along
- * with the Send_Data. This will allow us to know when the partner
- * has actually received all the data so we can get an accurate
- * timing.
- *
- * On the partner side, if Send status is received, the partner will
- * know to echo the data. If Confirm status is received, the partner
- * will know to issued Confirmed and then get ready to receive
- * more data, since the partner won't be echoing.
- */
- {
- CM_SEND_TYPE send_type;
- if (one_way_flag != 1) {
- send_type = CM_SEND_AND_PREP_TO_RECEIVE;
- } else {
- send_type = CM_SEND_AND_CONFIRM;
- }
- cmsst(cm_conv_id,
- &send_type,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
- }
-
- length = size;
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
-
- if (one_way_flag != 1) {
- max_receive_len = size;
- do {
-
- cmrcv (cm_conv_id, /* Receive Data */
- buffer, /* Data Pointer */
- &max_receive_len, /* Size of Data Buffer */
- &what_received, /* returned - what received */
- &received_len, /* returned - length of data */
- &status_received, /* returned - status received */
- &rts_received, /* returned - request to send */
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) {
- cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
- }
-
- if (what_received != CM_NO_DATA_RECEIVED) {
- current_concurrent--;
- }
-
- } while ((status_received != CM_SEND_RECEIVED));
- /* Repeat the receive loop until SEND permission has been rcvd. */
-
- if (current_concurrent != 0) {
- fprintf(stderr,
- "ERROR.\n");
- fprintf(stderr,
- "Partner did not send the expected number of records.\n");
- }
- } else {
- }
-
- #ifndef TIME_NOT_SUPPORTED
- end_time = get_time(); /* stop timer */
-
- elapsed_time = end_time - start_time; /* calculate elapsed time */
-
- printf("%16ld", elapsed_time);
- printf("%17lu", size * number_concurrent * one_way_flag);
-
- if (elapsed_time) {
- data_rate = /* in KBytes / 0.1 Sec */
- (double)
- ( ( (((double)size * (double)number_concurrent) / (double)1024) *
- (double)1 * (double)1000 * (double)one_way_flag)
- / /* divided by */
- ( (double)elapsed_time / (double)10) );
-
- data_rate = data_rate / (double)10;
-
- printf("%17.1f", data_rate);
- printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
-
- } else {
- printf("\n"); /* Make sure we move to next line*/
- }
-
- total_time += elapsed_time; /* accumulate the elapsed time */
-
- if (elapsed_time > max_time) {
- max_time = elapsed_time; /* set the max time */
- }
- if (elapsed_time < min_time) {
- min_time = elapsed_time; /* set the min time */
- }
- #else
- printf("Ping completed\n");
- #endif
-
- }
-
- {
- CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
- cmsdt(cm_conv_id,
- &deallocate_type,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSDT, cm_rc);
- }
-
- cmdeal(cm_conv_id,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
-
- /* destroy the object we created with cpicinit_new() */
- cpicinit_destroy(cpicinit);
-
- /* destroy the object we created with cpicerr_new() */
- cpicerr_destroy(cpicerr);
-
- exit_processing(); /* to avoid losing printouts */
- /* if redirected. */
- exit(EXIT_SUCCESS); /* force exit_list processing */
-
- }
-
- void
- process_arguments(int argc,
- char *argv[],
- CPICINIT * cpicinit)
- {
- int c; /* flag specifed, used w/getopt */
-
- /*
- * GETOPT is an easy way to parse command line arguments
- * Each parameter which can have a flag is passed in the third argument
- * to getopt. Getopt returns the character of the flag on the command
- * line and sets optarg to point to the value associated with the flag.
- * optind is the index of the argument that getopt is currently processing.
- */
- while (optind != argc) {
- c = getopt(argc, argv, "?1c:t:m:i:s:u:p:C:T:M:I:S:U:P:nN");
- switch (c) {
- case EOF:
- optarg = argv[optind];
- if (optarg[0] == '?') {
- show_info(usage);
- exit(EXIT_FAILURE);
- }
- optind++;
- if (cpicinit->set_destination == NOT_SET) {
- cpicinit_set_destination(cpicinit, optarg);
- } else {
- fprintf(stderr, "Only one destination may be specified.\n");
- }
- break;
- case 'M':
- case 'm':
- cpicinit_set_mode_name(cpicinit, optarg);
- break;
- case 'T':
- case 't':
- cpicinit_set_tp_name(cpicinit,optarg);
- break;
- case 'U':
- case 'u':
- cpicinit_set_userid(cpicinit, optarg);
- break;
- case 'P':
- case 'p':
- cpicinit_set_passwd(cpicinit, optarg);
- break;
- case 'N':
- case 'n':
- cpicinit_set_security_none(cpicinit);
- break;
- case 'S':
- case 's':
- size = atol(optarg); /* get the size of send blocks */
- if (size > MAX_SIZE) { /* check bounds */
- printf("Size (-s) of %lu too large.\n"
- "Setting to %lu\n", size, (unsigned long)MAX_SIZE);
- size = MAX_SIZE; /* reset to MAX */
- }
- break;
- case 'I':
- case 'i':
- number_iterations = atol(optarg);
- break;
- case 'C':
- case 'c':
- number_concurrent = atol(optarg);
- break;
- case '1':
- one_way_flag = 1;
- break;
- case '?':
- show_info(usage);
- exit(EXIT_FAILURE);
- break;
- default:
- printf("Invalid flag. Use %s -? for usage\n", PROGRAM_NAME);
- exit(EXIT_FAILURE);
- }
- }
- }
-
-
- #ifndef TIME_NOT_SUPPORTED
- ULONG
- /* returns time in milliseconds */
- get_time(void)
- {
-
- #if defined(OS2) || defined(FAPI) || defined(DOS)
- /*
- * clock() returns valid information on OS/2 and DOS since no distinction
- * is made between process time and time of day.
- */
- clock_t time;
- time = clock();
- return (time / (CLK_TCK / 1000));
- #elif defined(AIX)
- time_t ltime;
- struct timestruc_t TimeStruct;
-
- if (gettimer(TIMEOFDAY, &TimeStruct) == 0) {
- return ((1000 * TimeStruct.tv_sec) + (TimeStruct.tv_nsec / 1000000));
- } else {
- time(<ime);
- return 1000 * ltime;
- }
-
- #else
- /*
- * Other systems must use the time() calls to get the time of day in
- * seconds. This results in very coarse timings.
- */
- time_t ltime;
- time(<ime);
- return 1000 * ltime;
- #endif
-
- }
- #endif
-
- void handler(int sig)
- {
- /*=========================================================================
- * This is the signal handler.
- * Input parameter "sig" is not used, but required by the function
- * prototype for the signal() library call.
- *=======================================================================*/
-
- (void)signal(SIGINT, SIG_IGN);
- exit_processing();
- exit(EXIT_FAILURE);
- }
-
-
- void exit_processing(void)
- /*
- * Print out the grand totals and max/min times.
- */
- {
-
- double data_rate;
- static int beenhere = 0;
-
-
- #ifndef TIME_NOT_SUPPORTED
- if (!beenhere) { /* avoid being printing twice */
- beenhere = 1;
-
- if (total_time > 10) {
-
- data_rate = /* in KBytes / 0.1 Sec */
- (double)
- ( ( (((double)size * (double)number_concurrent) / (double)1024) *
- (double)current_iteration * (double)1000 * (double)one_way_flag)
- / /* divided by */
- ( (double)total_time / (double)10) );
-
- data_rate = data_rate / 10;
-
- printf("Totals:%9lu", total_time);
- printf("%17lu", size *
- number_concurrent *
- current_iteration *
- one_way_flag);
- printf("%17.1f", data_rate);
- printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
- if (current_iteration > 0) {
- printf(
- "\nDuration statistics: Min = %lu Ave = %lu Max = %lu\n",
- min_time,
- total_time / current_iteration,
- max_time);
- }
- } else {
- printf("\n");
- }
- }
- #endif
-
- }
-
-